package zwp.example.demo1.demo_thread_pool.impl;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import zwp.example.demo1.demo_thread_pool.DemoSleepAndWaitService;

import java.util.concurrent.*;

/**
 * @author zwp14
 * 线程睡眠和等待业务实现
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class DemoSleepAndWaitServiceImpl
        implements DemoSleepAndWaitService {


    /**
     * 创建简单的对象作为锁，保证唯一性即可
     */
    private static final Object LOCK = new Object();
    private final ThreadPoolTaskExecutor executor;

    /**
     * 线程睡眠
     *
     * @return 成功标识
     */
    @Override
    public String sleepTest() {
        log.info("Thread sleep start!");
        try {
            Thread.sleep(9000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.info("Thread sleep stop!");
        return "Sleep test success!";
    }


    /**
     * 显式创建线程
     */
    @Override
    public void waitTest1() {
        //创建两个线程
        //线程1-等待唤醒线程
        Thread waitNotifyThread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (LOCK) {
                    try {
                        log.info("Current thread wait notify!");
                        LOCK.wait();
                        log.info("Current thread is notify!");
                        System.out.println("线程被唤醒后执行的这句话！");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
        //线程2-唤醒线程
        Thread notificationThread = new Thread(() -> {

            try {
                log.info("耗时6s");
                Thread.sleep(6000);
                synchronized (LOCK){
                    log.info("send notify message!");
                    LOCK.notifyAll();
                }

            } catch (InterruptedException e) {
                e.printStackTrace();
            }


        });

        waitNotifyThread.start();
        notificationThread.start();
        synchronized (LOCK){
            try {
                log.info("主线程等待！");
                LOCK.wait();
                log.info("主线程被唤醒继续执行！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 使用Spring框架中的 ThreadPoolTaskExecutor创建线程
     */
    @Override
    public void waitTest2(){
        Runnable wait = ()->{
            synchronized (LOCK){
                log.info("wait notification!");
                try {
                    LOCK.wait();
                    log.info("wait notification success!!");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Runnable send = getRunnable();

        //将任务交给线程池去执行
        executor.execute(wait);
        //交给线程池执行并拿到结果
        executor.submit(send);
        synchronized (LOCK){
            try {
                log.info("主线程等待被唤醒。。。");
                LOCK.wait();
                log.info("主线程被唤醒，继续执行！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 使用Java标准库中的 ThreadPoolExecutor手动创建线程
     */
    @Override
    public void waitTest3(){
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                //核心线程数
                2,
                //最大线程数
                5,
                //线程存活时间
                9000,
                //时间单位
                TimeUnit.SECONDS,
                //阻塞队列
                new ArrayBlockingQueue<>(10),
                //线程工厂
                Executors.defaultThreadFactory(),
                //拒绝策略--丢弃等待时间最长的任务
//                new ThreadPoolExecutor.DiscardOldestPolicy()
                new ThreadPoolExecutor.CallerRunsPolicy() //由调用者执行
        );

        CompletableFuture.runAsync(
                ()->{
                    synchronized (LOCK){
                        log.info("wait notification!");
                        try {
                            LOCK.wait();
                            log.info("wait notification success!!");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                },threadPoolExecutor
        );

        CompletableFuture.runAsync(
                getRunnable(),threadPoolExecutor
        );
        synchronized (LOCK){
            try {
                log.info("主线程等待被唤醒。。。");
                LOCK.wait();
                log.info("主线程被唤醒，继续执行！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 使用Spring框架中的ThreadPoolTaskExecutor手动创建线程池
     */
    @Override
    public void waitTest4(){
        //核心线程数
        executor.setCorePoolSize(2);
        //最大线程数
        executor.setMaxPoolSize(5);
        //阻塞队列
        executor.setQueueCapacity(100);
        //配置线程池中线程名称的前缀
        executor.setThreadNamePrefix("zwp-test-async-service-");
        //拒绝策略--由调用者去执行
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        Runnable wait = ()->{
            String name = Thread.currentThread().getName();
            synchronized (LOCK){
                try {
                    log.info(name+"线程开始等待！");
                    LOCK.wait();
                    log.info(name+"线程被唤醒！");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        };

        Runnable notify = ()->{
            String name = Thread.currentThread().getName();
            try {
                log.info(name+"线程睡眠5秒！");
                Thread.sleep(5000);
                log.info(name+"线程睡眠结束！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (LOCK){
                log.info(name+"线程获取到锁，开始唤醒等待中的线程");
                LOCK.notifyAll();
                log.info(name+"线程唤醒操作成功！");
            }
        };
        executor.execute(wait);
        executor.execute(notify);
        String name = Thread.currentThread().getName();
        synchronized (LOCK){
            try {
                log.info("调用者"+name+"获取到Lock，等待被唤醒！");
                LOCK.wait();
                log.info("调用者"+name+"继续执行！");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


    private Runnable getRunnable() {
        return () -> {
            try {
                log.info("send method sleep 5s");
                Thread.sleep(5000);
                log.info("send method sleep stop!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            synchronized (LOCK) {
                log.info("send notification!");
                LOCK.notifyAll();
                log.info("send notification success!!");
            }
        };
    }

}
